import json
import re
import time

import requests

from datetime_utils import now, make_date
from request_base import RequestCookiesHandler, headers_base, save_file, parser_query

from utils import print_qr, QR_IMAGE_PATH, RESULT_DATA_PATH, DETAIL_DATA_PATH, COOKIES_FILE_PATH
from logging_config import get_logger

logger = get_logger()


class LoginWx:
    def __init__(self, session, cookies_handler):
        self.session = session
        self.cookies_handler = cookies_handler
        self.login_url = "https://open.weixin.qq.com/connect/qrconnect?appid=wx5cb34fe58d130615&scope=snsapi_login&redirect_uri=https%3A%2F%2Fa.weixin.qq.com%2Findex.html&state=test&login_type=jssdk&self_redirect=default&styletype=&sizetype=&bgcolor=&rst=&href=https://wximg.qq.com/wxp/assets/css/agencyweb_login_v2.css"

    def login(self):
        if self.get_check_login():
            return True

        self.session.cookies.clear()
        while True:
            # 获取二维码/进行扫描
            uuid = self.getQRuuid()
            if uuid:
                logger.info('Getting uuid of QR code. %s', uuid)

                self.getQrcode(uuid)
                logger.info('Downloading QR code.')
                logger.info('Please scan the QR code to log in.')
                isLoggedIn = False
                last = None
                while not isLoggedIn:
                    # 检查是否扫描成功
                    status, code = self.check_login(uuid, last)
                    last = None
                    if status == '405' and code:  # 扫码了,获取code
                        logger.info('Loading the contact, this may take a little while.')
                        isLoggedIn = True
                    elif status == '408':  # 没有扫码 继续等待
                        pass
                    elif status == '404':  # 没有扫码 继续等待
                        last = "404"
                    elif status == '0':  # 获取扫码结果失败
                        logger.info("获取扫码结果失败")
                        isLoggedIn = None
                        break
                    elif status == '402':  # 二维码已失效 重新获取二维码
                        break
                    time.sleep(1)
                if isLoggedIn:
                    break
                elif isLoggedIn is False:
                    logger.info('Login time out, reloading QR code.')
            time.sleep(1)
        r = self.getAuthCookies(code)
        if self.get_check_login():
            self.cookies_handler.save_cookie()
            return True

    def get_check_login(self):
        url = "https://a.weixin.qq.com/cgi-bin/agency/check_login"
        params = {
            'g_tk': self.cookies_handler.cookies_to_tk(),
            '_': now()
        }
        logger.info("check login url [%s]", url)
        result = self.session.get(url, params=params, headers=headers_base)
        if result.ok:
            d = result.json()
            logger.info("check login result %s", d)
            ret = d.get('ret')
            if ret == 0:
                return True
            return False
        return None

    def getQRuuid(self):
        """
        请求login url 解析除二维码的uuid
        :return: 二维码的uuid
        """
        _headers = {"Referer": "https://a.weixin.qq.com/adres/htmledition/agency/index.html"}
        _headers.update(headers_base)
        response = self.session.get(self.login_url, headers=_headers)

        # <img class="qrcode lightBorder" src="/connect/qrcode/021Ze5NWC6F-dahk" />
        if response.ok:
            regx = r'<img class="qrcode lightBorder" src="/connect/qrcode/(.*?)" />'
            data = re.search(regx, response.text)
            if data:
                return data.group(1)

    def getQrcode(self, QRuuid):
        """
        通过uuid参数,获取二维码,并显示出来
        :param QRuuid: 二维码的uuid
        :return: 显示二维码
        """
        url = "https://open.weixin.qq.com/connect/qrcode/" + QRuuid
        r = self.session.get(url, headers=headers_base)
        if r.ok:
            with open(QR_IMAGE_PATH, 'wb') as f:
                f.write(r.content)
            print_qr(QR_IMAGE_PATH)

    def check_login(self, uuid, last=None):
        """
        循环检测二维码是否被扫码及扫码结果
        :param uuid: 二维码uuid
        :param last: 最后一次状态
        :return: 是否扫码成功和wx_code
        """
        # 1560559750033
        params = {"uuid": uuid, "_": now()}
        # last=404
        if last is not None:
            params["last"] = last

        url = "https://long.open.weixin.qq.com/connect/l/qrconnect"

        _headers = {"Referer": self.login_url}
        _headers.update(headers_base)
        result = self.session.get(url, params=params, headers=_headers)
        regx = "window.wx_errcode=(\d+);window.wx_code='(.*?)';"
        if result.ok:
            logger.info("扫码结果 [%s]", result.text)
            d = re.search(regx, result.text)
            if d:
                errcode, code = d.group(1), d.group(2)
                logger.info("扫码结果 err_code %s, wx_code %s", errcode, code)
                return errcode, code
        return 0, ""

        # window.wx_errcode=408;window.wx_code='';
        # window.wx_errcode=405;window.wx_code='001NlGJY160oLT0G7OKY14lkJY1NlGJZ';
        # window.wx_errcode=405;window.wx_code='061jgXyB00mLRg28yiyB0oHWyB0jgXy2';
        # window.wx_errcode=402;window.wx_code='';  12次 变成 402

    def getAuthCookies(self, code):
        """
        请求 cgi 设置 cookies
        :param code: wx_code
        :return: 返回请求结果
        """
        url = "https://a.weixin.qq.com/cgi-bin/agency/login_auth"
        _headers = {
            "Host": "a.weixin.qq.com",
            "Referer": "https://a.weixin.qq.com/index.html?code=%s&state=test" % code
        }
        _headers.update(headers_base)
        result = self.session.post(url, headers=_headers, data={"code": code})
        if result.ok:
            logger.info(result.text)
        return result


class SpiderWx:
    def __init__(self, session, cookies_handler):
        self.session = session
        self.cookies_handler = cookies_handler

    def get_metrics(self):
        url = "https://a.weixin.qq.com/cgi-bin/agency/get_delivery_metrics"
        params = {
            "page": "1",
            "page_size": "10",
            "search_key": "",
            "order_by": "yesterday_cost",
            "ascending": "0",
            "only_collect": "0",
            "g_tk": self.cookies_handler.cookies_to_tk(),
            "_": now(),
        }
        r = self.session.get(url, params=params, headers=headers_base)
        if r.ok:
            return r.json()

    def get_all_data(self, data):
        detail = {}
        for i in data['list']:
            if i['yesterday_cost'] > 0:
                name, appid = i['mp_name'], i['appid']
                logger.info("parser %s -> %s", name, appid)
                r = self.get_redict(appid)
                if r is None:
                    logger.warn('result %s is None', appid)
                detail[appid] = {'name': name, 'data': r}
                time.sleep(2)
        return detail

    def parser_data(self, data):
        result = []
        for v in data.values():
            _d = {'昵称': v['name']}
            for d in v['data'].get('list', []):
                _t = {}
                clk = d['campaign3_index']['clk_pv']
                if clk == 0:
                    continue
                _t['点击次数'] = clk
                _t['广告id'] = d['all_status']['aid']
                _t['广告标题'] = d['material_info']['title']
                _t['广告图片'] = d['material_info']['image_url']
                _t['当前出价'] = d['campaign3_index']['bid_avg']
                _t['花费/元'] = d['campaign3_index']['paidfen']
                _t['曝光次数'] = d['campaign3_index']['exp_pv']
                _t['点击率'] = d['campaign3_index']['ctr']
                _t['投放开始时间'] = d['campaign_info']['begin_time']
                _t['投放结束时间'] = d['campaign_info']['end_time']
                _t['广告预算/角'] = d['campaign_info']['budget']
                _t['点击均价'] = _t['花费/元'] / _t['点击次数']
                _t.update(_d)
                result.append(_t)
        return result

    def get_appid_detail(self, token):
        args = {'op_type': 1,
                'where': {},
                'page': 1,
                'page_size': 20,
                'pos_type': 997,
                'advanced': True,
                'query_index': '["material_preview","day_budget","cname","product_type","contract_flag","status","exposure_score","budget","bid_action_type","bid","bid_avg","paid","exp_pv","clk_pv","ctr","comindex","cpa","begin_time","end_time"]',
                }
        args.update(make_date())
        params = {
            "action": "get_campaign_data",
            "token": token,
            "appid": "",
            "spid": "",
            "args": json.dumps(args, separators=(',', ':')),
            "_": now(),
        }
        _headers = {
            "Host": "mp.weixin.qq.com",
            "Referer": "https://mp.weixin.qq.com/promotion/frame?t=ad_system/common_frame&t1=campaign/manage&token=%s&type=3" % token
        }
        _headers.update(headers_base)
        # https://mp.weixin.qq.com/promotion/as_rock?action=get_adgroup_data&args=%7B%22op_type%22%3A1%2C%22where%22%3A%7B%7D%2C%22page%22%3A1%2C%22page_size%22%3A20%2C%22pos_type%22%3A997%2C%22advanced%22%3Atrue%2C%22create_time_range%22%3A%7B%22start_time%22%3A1552579231%7D%2C%22query_index%22%3A%22%5B%5C%22material_preview%5C%22%2C%5C%22day_budget%5C%22%2C%5C%22cname%5C%22%2C%5C%22product_type%5C%22%2C%5C%22contract_flag%5C%22%2C%5C%22status%5C%22%2C%5C%22exposure_score%5C%22%2C%5C%22budget%5C%22%2C%5C%22bid%5C%22%2C%5C%22paid%5C%22%2C%5C%22exp_pv%5C%22%2C%5C%22clk_pv%5C%22%2C%5C%22ctr%5C%22%2C%5C%22cpc%5C%22%2C%5C%22begin_time%5C%22%2C%5C%22end_time%5C%22%5D%22%2C%22time_range%22%3A%7B%22start_time%22%3A1560441600%2C%22last_time%22%3A1560527999%7D%7D&token=12537399&appid=&spid=&_=1560664471322
        url = "https://mp.weixin.qq.com/promotion/as_rock"
        return session.get(url, params=params, headers=_headers)

    def get_redict(self, appid):
        url = "http://a.weixin.qq.com/cgi-bin/agency/redirect_mp"
        params = {
            "appid": appid,
            "g_tk": self.cookies_handler.cookies_to_tk(),
            "mgr_type": "1",
        }
        result = session.get(url, params=params, headers=headers_base)
        if result.ok:
            token = parser_query(result.url).get('token')
            detail_result = self.get_appid_detail(token)
            if detail_result.ok:
                return detail_result.json()
        return None


if __name__ == "__main__":
    session = requests.Session()
    cookies_handler = RequestCookiesHandler(session, COOKIES_FILE_PATH)
    cookies_handler.load_cookies()
    wx = LoginWx(session, cookies_handler)
    if wx.login():
        logger.info("微信登陆成功")
        spider = SpiderWx(session, cookies_handler)
        # 获取昨天数据
        data = spider.get_metrics()

        detail_data = spider.get_all_data(data)
        result_data = spider.parser_data(detail_data)

        save_file(detail_data, DETAIL_DATA_PATH)
        save_file(result_data, RESULT_DATA_PATH)
